home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_demo / bd3.ada next >
Text File  |  1996-01-30  |  20KB  |  541 lines

  1. package BANK is
  2. --------------------------------------------------------------------------
  3. --| BEGIN PROLOGUE
  4. --| DESCRIPTION            : BANK defines a bank, the TELLER objects
  5. --|                        : within it, and the procedure PRINT_REPORT
  6. --|                        : (which reports on the status of the BANK).
  7. --|                        :
  8. --|                        : BANK is an abstract state machine, defining
  9. --|                        : a BANK object which contains TELLER objects.
  10. --|                        :
  11. --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
  12. --|                        : object-oriented design and tasking
  13. --|                        : with Ada
  14. --|                        :
  15. --| LIMITATIONS            : None
  16. --| AUTHOR(S)              : Richard Conn (RLC)
  17. --| CHANGE LOG             : 1/16/89  RLC  Initial Design and Code
  18. --| CHANGE LOG             : 2/25/89  RLC  Final Review Prior to Release
  19. --| REMARKS                : None
  20. --| PORTABILITY ISSUES     : None
  21. --| END PROLOGUE
  22. --------------------------------------------------------------------------
  23.  
  24.     -- TRANSACTION requested of a TELLER
  25.     type TRANSACTION  is (ADD_NEW_CUSTOMER,
  26.                           GET_BALANCE,
  27.                           MAKE_DEPOSIT,
  28.                           MAKE_WITHDRAWAL);
  29.  
  30.     -- Unit of currency
  31.     type DOLLAR       is new FLOAT;
  32.  
  33.     -- Identification of a CUSTOMER
  34.     type CUSTOMER_ID  is new NATURAL range 1 .. NATURAL'LAST;
  35.  
  36.     -- Index of and Number of TELLER objects within the bank
  37.     type TELLER_INDEX is new NATURAL range 1 .. 4;
  38.  
  39.     -- A TELLER_PERSON is an object to which a CUSTOMER may make a REQUEST
  40.     -- The BANK tells the TELLER_PERSON to START_WORK, giving the
  41.     -- TELLER_PERSON its TELLER_NUMBER
  42.     task type TELLER_PERSON is
  43.     entry REQUEST(ID     : in out CUSTOMER_ID;
  44.               KIND   : in TRANSACTION;
  45.               AMOUNT : in out DOLLAR);
  46.     end TELLER_PERSON;
  47.     -- These are the TELLER objects available at the bank
  48.     TELLER : array(TELLER_INDEX) of TELLER_PERSON;
  49.  
  50.     -- PRINT_REPORT gives the transaction log of all the bank
  51.     -- customers
  52.     procedure PRINT_REPORT;
  53.  
  54.     -- STOP_WORK terminates all TELLER tasks
  55.     procedure STOP_WORK;
  56. end BANK;
  57. -- 
  58. with CONSOLE;
  59. package body BANK is
  60. --------------------------------------------------------------------------
  61. --| BEGIN PROLOGUE
  62. --| DESCRIPTION            : Package Body BANK implements the TELLER
  63. --|                        : tasks and the PRINT_REPORT procedure.
  64. --|                        : CUSTOMER data is maintained within the
  65. --|                        : BANK as a linked list.
  66. --|                        :
  67. --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
  68. --|                        : object-oriented design and tasking
  69. --|                        : with Ada
  70. --|                        :
  71. --| LIMITATIONS            : None
  72. --| AUTHOR(S)              : Richard Conn (RLC)
  73. --| CHANGE LOG             : 1/16/89  RLC  Initial Design and Code
  74. --| CHANGE LOG             : 2/25/89  RLC  Final Review Prior to Release
  75. --| REMARKS                : None
  76. --| PORTABILITY ISSUES     : Uses CONSOLE (TEXT_IO), so is very portable;
  77. --|                        : no known portability problems.
  78. --| END PROLOGUE
  79. --------------------------------------------------------------------------
  80.  
  81.     -- Identifier of next customer
  82.     NEXT_ID                  : CUSTOMER_ID           := CUSTOMER_ID'FIRST;
  83.  
  84.     -- Linked list of customer data
  85.     type CUSTOMER_DATA;
  86.     type CUSTOMER_DATA_POINTER is access CUSTOMER_DATA;
  87.     type CUSTOMER_DATA is record
  88.     ID                  : CUSTOMER_ID;
  89.     BALANCE             : DOLLAR                := 0.0;
  90.     TRANSACTION_COUNT   : NATURAL               := 0;
  91.     ATTEMPTED_OVERDRAWS : NATURAL               := 0;
  92.     NEXT                : CUSTOMER_DATA_POINTER := null;
  93.     end record;
  94.  
  95.     -- Count of number of transactions for each TELLER object
  96.     TELLER_TRANSACTION_COUNT : array(TELLER_INDEX) of NATURAL 
  97.       := (others => 0);
  98.  
  99.     -- Pointers to first and last customer data entries
  100.     FIRST_CUSTOMER           : CUSTOMER_DATA_POINTER := null;
  101.     LAST_CUSTOMER            : CUSTOMER_DATA_POINTER := null;
  102.  
  103. -- 
  104. -- package body BANK
  105.     -- Print a report of the status of the BANK
  106.     procedure PRINT_REPORT is
  107.     CURRENT_CUSTOMER : CUSTOMER_DATA_POINTER;
  108.     begin
  109.  
  110.         -- Check for any customers and issue an error message if none
  111.     if NEXT_ID = CUSTOMER_ID'FIRST then
  112.         CONSOLE.WRITE("The bank doesn't have any customers");
  113.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  114.  
  115.         -- Generate report
  116.     else
  117.  
  118.             -- Customer balance, transaction count, attempted overdraw
  119.             -- count report
  120.         CONSOLE.WRITE("**** BANK STATUS REPORT ****");
  121.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  122.         CONSOLE.WRITE(
  123.               "Customer      Balance  Transactions  Attempted_Overdraws");
  124.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  125.         CURRENT_CUSTOMER := FIRST_CUSTOMER;
  126.         while CURRENT_CUSTOMER /= null loop
  127.         CONSOLE.WRITE(INTEGER(CURRENT_CUSTOMER.ID), 5);
  128.         CONSOLE.WRITE("     ");
  129.         CONSOLE.WRITE(FLOAT(CURRENT_CUSTOMER.BALANCE), 8, 2);
  130.         CONSOLE.WRITE("      ");
  131.         CONSOLE.WRITE(INTEGER(CURRENT_CUSTOMER.TRANSACTION_COUNT), 8);
  132.         CONSOLE.WRITE("             ");
  133.         CONSOLE.WRITE(INTEGER(CURRENT_CUSTOMER.ATTEMPTED_OVERDRAWS),
  134.           8);
  135.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  136.         CURRENT_CUSTOMER := CURRENT_CUSTOMER.NEXT;
  137.         end loop;
  138.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  139.  
  140.             -- Teller transaction count report
  141.         CONSOLE.WRITE("Teller           : ");
  142.         for I in TELLER_INDEX loop
  143.         CONSOLE.WRITE(INTEGER(I), 8);
  144.         end loop;
  145.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  146.         CONSOLE.WRITE("Transaction_Count: ");
  147.         for I in TELLER_INDEX loop
  148.         CONSOLE.WRITE(INTEGER(TELLER_TRANSACTION_COUNT(I)), 8);
  149.         end loop;
  150.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  151.  
  152.     end if;
  153.     end PRINT_REPORT;
  154.  
  155.     -- Terminate all TELLER tasks
  156.     procedure STOP_WORK is
  157.     begin
  158.     for I in TELLER_INDEX loop
  159.         abort TELLER(I);
  160.     end loop;
  161.     end STOP_WORK;
  162. -- 
  163. -- package body BANK
  164.  
  165.     -- FIND_CUSTOMER is used to find a CUSTOMER_DATA record
  166.     -- based on a CUSTOMER_ID number
  167.     function FIND_CUSTOMER(ID : in CUSTOMER_ID)
  168.                 return CUSTOMER_DATA_POINTER is
  169.     CURRENT_CUSTOMER : CUSTOMER_DATA_POINTER;
  170.     begin
  171.     CURRENT_CUSTOMER := FIRST_CUSTOMER;
  172.     while CURRENT_CUSTOMER /= null loop
  173.         exit when CURRENT_CUSTOMER.ID = ID;
  174.         CURRENT_CUSTOMER := CURRENT_CUSTOMER.NEXT;
  175.     end loop;
  176.     return CURRENT_CUSTOMER;
  177.     end FIND_CUSTOMER;
  178.  
  179.  
  180. -- 
  181. -- package body BANK
  182.  
  183.     task TELLER_ASSIGNER is
  184.     -- This task assigns an ID number to a teller.
  185.     -- TELLER_ASSIGNER is called by the TELLER_PERSON task when the
  186.     -- TELLER_PERSON task first starts up.
  187.     entry GET_TELLER_ID(ID : out TELLER_INDEX);
  188.     end TELLER_ASSIGNER;
  189.  
  190.     task body TELLER_ASSIGNER is
  191.     NEXT_TELLER_ID : TELLER_INDEX := TELLER_INDEX'FIRST;
  192.     begin
  193.     loop
  194.         accept GET_TELLER_ID(ID : out TELLER_INDEX) do
  195.         ID := NEXT_TELLER_ID;
  196.         if NEXT_TELLER_ID /= TELLER_INDEX'LAST then
  197.             NEXT_TELLER_ID := NEXT_TELLER_ID + 1;
  198.         end if;
  199.         end GET_TELLER_ID;
  200.     end loop;
  201.     end TELLER_ASSIGNER;
  202.  
  203. -- 
  204. -- package body BANK
  205.  
  206.     -- Implementation of a TELLER task
  207.     task body TELLER_PERSON is
  208.  
  209.     THIS_CUSTOMER : CUSTOMER_DATA_POINTER;
  210.     MY_NUMBER     : TELLER_INDEX;
  211.  
  212.     begin
  213.  
  214.         -- TELLER gets his ID number
  215.     TELLER_ASSIGNER.GET_TELLER_ID(MY_NUMBER);
  216.  
  217.         -- TELLER loops on REQUESTs from CUSTOMERs
  218.     loop
  219.         accept REQUEST(ID     : in out CUSTOMER_ID;
  220.                KIND   : in TRANSACTION;
  221.                AMOUNT : in out DOLLAR) do
  222.  
  223.                 -- Increment teller's transaction count
  224.         TELLER_TRANSACTION_COUNT(MY_NUMBER)
  225.                     := TELLER_TRANSACTION_COUNT(MY_NUMBER) + 1;
  226.  
  227. -- 
  228. -- package body BANK
  229.  
  230.                 -- Process REQUEST
  231.         case KIND is
  232.  
  233.             when ADD_NEW_CUSTOMER =>
  234.             if LAST_CUSTOMER = null then
  235.                 LAST_CUSTOMER := new CUSTOMER_DATA;
  236.                 FIRST_CUSTOMER := LAST_CUSTOMER;
  237.             else
  238.                 LAST_CUSTOMER.NEXT := new CUSTOMER_DATA;
  239.                 LAST_CUSTOMER := LAST_CUSTOMER.NEXT;
  240.             end if;
  241.             LAST_CUSTOMER.ID := NEXT_ID;
  242.             ID := NEXT_ID;
  243.             NEXT_ID := NEXT_ID + 1;
  244.             THIS_CUSTOMER := LAST_CUSTOMER;
  245.  
  246.             when GET_BALANCE =>
  247.             THIS_CUSTOMER := FIND_CUSTOMER(ID);
  248.             AMOUNT := THIS_CUSTOMER.BALANCE;
  249.  
  250.             when MAKE_DEPOSIT =>
  251.             THIS_CUSTOMER := FIND_CUSTOMER(ID);
  252.             THIS_CUSTOMER.BALANCE
  253.                             := THIS_CUSTOMER.BALANCE + AMOUNT;
  254.             AMOUNT := THIS_CUSTOMER.BALANCE;
  255.  
  256.             when MAKE_WITHDRAWAL =>
  257.             THIS_CUSTOMER := FIND_CUSTOMER(ID);
  258.             if THIS_CUSTOMER.BALANCE < AMOUNT then
  259.                 AMOUNT := 0.0;
  260.                 THIS_CUSTOMER.ATTEMPTED_OVERDRAWS :=
  261.                   THIS_CUSTOMER.ATTEMPTED_OVERDRAWS + 1;
  262.             else
  263.                 THIS_CUSTOMER.BALANCE
  264.                                 := THIS_CUSTOMER.BALANCE - AMOUNT;
  265.             end if;
  266.  
  267.         end case;
  268.  
  269.                 -- Increment CUSTOMER's transaction count
  270.         THIS_CUSTOMER.TRANSACTION_COUNT
  271.                     := THIS_CUSTOMER.TRANSACTION_COUNT + 1;
  272.  
  273.         end REQUEST;
  274.  
  275.     end loop;
  276.  
  277.     end TELLER_PERSON;
  278.  
  279. end BANK;
  280.  
  281. -- 
  282. package CUSTOMER_WORLD is
  283. --------------------------------------------------------------------------
  284. --| BEGIN PROLOGUE
  285. --| DESCRIPTION            : CUSTOMER_WORLD is an abstract state machine
  286. --|                        : which defines the collection of all CUSTOMERs
  287. --|                        : of the BANK.  It allows the mainline procedure
  288. --|                        : to ADD a new CUSTOMER and TERMINATE_ALL
  289. --|                        : current CUSTOMERs.  The CUSTOMER itself acts
  290. --|                        : as an independent task and requires no
  291. --|                        : direct interaction with the mainline once
  292. --|                        : it starts.
  293. --|                        :
  294. --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
  295. --|                        : object-oriented design and tasking
  296. --|                        : with Ada
  297. --|                        :
  298. --| LIMITATIONS            : None
  299. --| AUTHOR(S)              : Richard Conn (RLC)
  300. --| CHANGE LOG             : 1/16/89  RLC  Initial Design and Code
  301. --| CHANGE LOG             : 2/25/89  RLC  Final Review Prior to Release
  302. --| REMARKS                : None
  303. --| PORTABILITY ISSUES     : None
  304. --| END PROLOGUE
  305. --------------------------------------------------------------------------
  306.  
  307.     -- Add another CUSTOMER task to the system
  308.     procedure ADD;
  309.  
  310.     -- Terminate all CUSTOMERs in the system
  311.     procedure TERMINATE_ALL;
  312.  
  313. end CUSTOMER_WORLD;
  314.  
  315. -- 
  316. with BANK;
  317. with RANDOM;
  318. package body CUSTOMER_WORLD is
  319.  
  320.     -- Support infix operations, like DOLLAR < DOLLAR
  321.     use  BANK;
  322.  
  323.     -- This is the amount that a CUSTOMER initially deposits
  324.     -- into his account
  325.     INITIAL_DEPOSIT : constant BANK.DOLLAR          := 100.0;
  326.  
  327.     -- A CUSTOMER is a task, running concurrently with the TELLERs,
  328.     -- other CUSTOMERs, and the mainline task
  329.     task type CUSTOMER;
  330.  
  331.     -- CUSTOMER_POINTER is a pointer to a CUSTOMER, used to
  332.     -- create new customers and track old customers in the linked
  333.     -- list of customers used for task termination when the
  334.     -- program is complete
  335.     type CUSTOMER_POINTER              is access CUSTOMER;
  336.  
  337.     -- These are the constructs used to create a linked list of
  338.     -- the customers
  339.     type CUSTOMER_LIST_ELEMENT;
  340.     type CUSTOMER_LIST_ELEMENT_POINTER is access CUSTOMER_LIST_ELEMENT;
  341.     type CUSTOMER_LIST_ELEMENT is record
  342.     THIS_CUSTOMER : CUSTOMER_POINTER;
  343.     NEXT          : CUSTOMER_LIST_ELEMENT_POINTER := null;
  344.     end record;
  345.  
  346.     -- Pointer to the first of the customers
  347.     FIRST_CUSTOMER  : CUSTOMER_LIST_ELEMENT_POINTER := null;
  348.     LAST_CUSTOMER   : CUSTOMER_LIST_ELEMENT_POINTER := null;
  349.  
  350. -- 
  351. -- package body CUSTOMER_WORLD
  352.  
  353.     -- Implementation of the CUSTOMER task
  354.     task body CUSTOMER is
  355.  
  356.     ID                 : BANK.CUSTOMER_ID   := BANK.CUSTOMER_ID'FIRST;
  357.     BALANCE            : BANK.DOLLAR        := 0.0;
  358.     AMOUNT             : BANK.DOLLAR        := 0.0;
  359.     MY_TRANSACTION     : BANK.TRANSACTION;
  360.  
  361.         -- SELECT_TELLER makes a random selection of one of the
  362.         -- BANK's tellers
  363.     function SELECT_TELLER return BANK.TELLER_INDEX is
  364.     begin
  365.         return BANK.TELLER_INDEX(
  366.                 RANDOM.NUMBER * FLOAT(BANK.TELLER_INDEX'LAST) + 1.0);
  367.     exception
  368.         when others =>
  369.         return BANK.TELLER_INDEX'LAST;
  370.     end SELECT_TELLER;
  371.  
  372.     begin    -- CUSTOMER activity
  373.  
  374.         -- As a new CUSTOMER, the first two transactions of the
  375.         -- CUSTOMER are to ask the TELLER to add him as a new
  376.         -- CUSTOMER and make an initial deposit
  377.     BANK.TELLER(SELECT_TELLER).REQUEST(ID, BANK.ADD_NEW_CUSTOMER,
  378.       BALANCE);
  379.     BALANCE := INITIAL_DEPOSIT;
  380.     BANK.TELLER(SELECT_TELLER).REQUEST(ID, BANK.MAKE_DEPOSIT, BALANCE);
  381.  
  382.         -- The rest of the life of the CUSTOMER is spent in the
  383.         -- these steps within the following loop:
  384.         --    (1) delay a random amount of time from 0 to 5 seconds
  385.         --    (2) compute a random amount from -$50 to +$50
  386.         --    (3) if the random amount is negative, attempt to
  387.         --        withdraw that amount; if positive, deposit that
  388.         --        amount
  389.     loop
  390.         delay DURATION(5.0 * RANDOM.NUMBER);
  391.         AMOUNT := BANK.DOLLAR(100.0 * RANDOM.NUMBER - 50.0);
  392.         if AMOUNT < DOLLAR'(0.0) then
  393.         MY_TRANSACTION := BANK.MAKE_WITHDRAWAL;
  394.         AMOUNT := -AMOUNT;
  395.         else
  396.         MY_TRANSACTION := BANK.MAKE_DEPOSIT;
  397.         end if;
  398.         BANK.TELLER(SELECT_TELLER).REQUEST(ID, MY_TRANSACTION, AMOUNT);
  399.     end loop;
  400.  
  401.     end CUSTOMER;
  402.  
  403. -- 
  404. -- package body CUSTOMER_WORLD
  405.  
  406.     -- Add a new CUSTOMER to the linked list
  407.     procedure ADD is
  408.     begin
  409.  
  410.         -- If the list is empty, start a new list
  411.     if LAST_CUSTOMER = null then
  412.         FIRST_CUSTOMER := new CUSTOMER_LIST_ELEMENT;
  413.         LAST_CUSTOMER := FIRST_CUSTOMER;
  414.  
  415.         -- If the list is not empty, add an element onto it
  416.     else
  417.         LAST_CUSTOMER.NEXT := new CUSTOMER_LIST_ELEMENT;
  418.         LAST_CUSTOMER := LAST_CUSTOMER.NEXT;
  419.     end if;
  420.  
  421.         -- Start a new CUSTOMER task
  422.     LAST_CUSTOMER.THIS_CUSTOMER := new CUSTOMER;
  423.  
  424.     end ADD;
  425.  
  426.     -- Terminate all CUSTOMER tasks by moving thru the linked list
  427.     -- and explicitly terminating the tasks pointed to by the list
  428.     -- elements.
  429.     procedure TERMINATE_ALL is
  430.     CURRENT_CUSTOMER : CUSTOMER_LIST_ELEMENT_POINTER;
  431.     begin
  432.     CURRENT_CUSTOMER := FIRST_CUSTOMER;
  433.     while CURRENT_CUSTOMER /= null loop
  434.         abort CURRENT_CUSTOMER.THIS_CUSTOMER.all;
  435.         CURRENT_CUSTOMER := CURRENT_CUSTOMER.NEXT;
  436.     end loop;
  437.     end TERMINATE_ALL;
  438.  
  439. end CUSTOMER_WORLD;
  440.  
  441. -- 
  442. with BANK;
  443. with CUSTOMER_WORLD;
  444. with CONSOLE;
  445. procedure BD3 is                           -- BANK_DEMO_3
  446. --------------------------------------------------------------------------
  447. --| BEGIN PROLOGUE
  448. --| DESCRIPTION            : Procedure BD3 (BANK DEMO 3) is a mainline
  449. --|                        : which demonstrates the operation of the
  450. --|                        : BANK.  Upon invocation, the console becomes
  451. --|                        : a command processor for the bank manager.
  452. --|                        : The bank manager can obtain the status of
  453. --|                        : the bank (balances, number of transactions,
  454. --|                        : and attempted overdraws of all customers
  455. --|                        : and number of transactions processed by all
  456. --|                        : tellers) in a single or continuous (group
  457. --|                        : of 11 over about one minute) display.
  458. --|                        : The user at the console can also cause new
  459. --|                        : Customer tasks to be created and shut down
  460. --|                        : the system.
  461. --|                        :
  462. --| REQUIREMENTS SUPPORTED : Bank Demonstration Program to show
  463. --|                        : object-oriented design and tasking
  464. --|                        : with Ada
  465. --|                        :
  466. --| LIMITATIONS            : None
  467. --| AUTHOR(S)              : Richard Conn (RLC)
  468. --| CHANGE LOG             : 1/16/89  RLC  Initial Design and Code
  469. --| CHANGE LOG             : 2/25/89  RLC  Final Review Prior to Release
  470. --| REMARKS                : None
  471. --| PORTABILITY ISSUES     : Uses CONSOLE (TEXT_IO), so is very portable;
  472. --|                        : no known portability problems.
  473. --| END PROLOGUE
  474. --------------------------------------------------------------------------
  475.  
  476.     -- Line input from the console
  477.     INPUT                               : CONSOLE.OUTSTRING;
  478.  
  479.     -- Number of continuous status reports displayed by the 'c'
  480.     -- command before control is returned to the console
  481.     NUMBER_OF_CONTINUOUS_STATUS_REPORTS : constant := 10;
  482.  
  483. -- 
  484. -- procedure BD3
  485.  
  486. begin                                      -- mainline
  487.  
  488.     -- This is the beginning of the main loop.  In this loop,
  489.     -- a list of commands is printed on the console, the user
  490.     -- at the console (as CUSTOMER 0) enters one of these commands
  491.     -- followed by striking the RETURN key, and the command is
  492.     -- processed.
  493.     loop
  494.  
  495.         -- Command listing and prompt
  496.     CONSOLE.WRITE("Enter");
  497.     CONSOLE.WRITE(CONSOLE.NEW_LINE);
  498.     CONSOLE.WRITE("  b for bank status");
  499.     CONSOLE.WRITE(CONSOLE.NEW_LINE);
  500.     CONSOLE.WRITE("  c for continuous bank status");
  501.     CONSOLE.WRITE(CONSOLE.NEW_LINE);
  502.     CONSOLE.WRITE("  s for start next customer");
  503.     CONSOLE.WRITE(CONSOLE.NEW_LINE);
  504.     CONSOLE.WRITE("  x for exit: ");
  505.     CONSOLE.READ(INPUT);
  506.  
  507.         -- Interpretation and execution of input command
  508.     case INPUT(1) is
  509.         when 'b' | 'c' =>              -- Short or continuous bank status
  510.                                        -- report
  511.         BANK.PRINT_REPORT;
  512.         if INPUT(1) = 'c' then
  513.             for I in 1 .. NUMBER_OF_CONTINUOUS_STATUS_REPORTS loop
  514.             delay 5.0;
  515.             BANK.PRINT_REPORT;
  516.                     CONSOLE.WRITE(CONSOLE.NEW_LINE);
  517.             end loop;
  518.         end if;
  519.  
  520.         when 's' =>                    -- Start up a new CUSTOMER
  521.         CUSTOMER_WORLD.ADD;
  522.  
  523.         when 'x' =>                      -- Exit program
  524.         CUSTOMER_WORLD.TERMINATE_ALL;    -- Kill CUSTOMER tasks
  525.         BANK.STOP_WORK;                  -- Kill TELLER tasks
  526.         exit;                            -- Exit loop
  527.  
  528.         when ' ' =>                    -- Non-error on a null input line
  529.         null;
  530.  
  531.         when others =>                 -- Other commands are invalid
  532.         CONSOLE.WRITE("Invalid Command: ");
  533.         CONSOLE.WRITE(CONSOLE.TRIM(INPUT));
  534.         CONSOLE.WRITE(CONSOLE.NEW_LINE);
  535.  
  536.     end case;
  537.  
  538.     end loop;
  539.  
  540. end BD3;
  541.